package factorytest.iflytek.com.einkiflytekfactorytest.BluetoothSco;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import factorytest.iflytek.com.einkiflytekfactorytest.common.SettingsUtils;
import factorytest.iflytek.com.einkiflytekfactorytest.device.DeviceAttr;
import factorytest.iflytek.com.einkiflytekfactorytest.utils.DebugLog;
import factorytest.iflytek.com.einkiflytekfactorytest.utils.ReflectUtils;


public class BluetoothScoManager {

    private final Context mContext;
    private final boolean mUseNewInterface;
    private AudioManager mAudioManager;

    private boolean isScoConnected = false;

    private int scoReconnectedCount = 0;
    private final static int MAX_scoReconnectedCount = 5;

    public static final int FORCE_NONE = 0;
    public static final int FORCE_SPEAKER = 1;
    public static final int FORCE_HEADPHONES = 2;
    public static final int FORCE_BT_SCO = 3;
    public static final int FORCE_BT_A2DP = 4;
    public static final int FORCE_WIRED_ACCESSORY = 5;
    public static final int FORCE_MIC = 15;
    public static final int FOR_INPUT = 7;
    public static final int FOR_OUTPUT = 8;

    private static final int MODE_MIC = 0;
    private static final int MODE_HEADSET = 1;
    private static final int MODE_BLUETOOTH = 2;
    private static final int MODE_SPEAKER = 0;
    private static final int MODE_NONE = 3;


    private OnBluetoothScoConnectedListener scoConnectedListener;

    public BluetoothScoManager(Context context) {
        this.mContext = context;
        mAudioManager = mContext.getSystemService(AudioManager.class);
        mUseNewInterface = ReflectUtils.getMethodWithNoException(mAudioManager, "stopBTScoAndResetInput") != null;
    }

    public boolean isUseNewInterface() {
        return mUseNewInterface;
    }

    public void setScoConnectedListener(OnBluetoothScoConnectedListener scoConnectedListener) {
        this.scoConnectedListener = scoConnectedListener;
    }

    public void startRecorderScoMode() {

        if (!DeviceAttr.getRunningDeviceAttr().hasBluetoothRecord()) {
            return;
        }

        stopRecorderScoMode();
        DebugLog.e("startRecorderScoMode....................");

        if (mUseNewInterface) {

            SettingsUtils.setBluetoothScoConnected(mContext, true);

            if (mAudioManager != null) {
                mAudioManager.setMode(AudioManager.MODE_IN_CALL);
            }

            if (scoConnectedListener != null) {
                scoConnectedListener.onBluetoothScoConnected(true);
            }

            setForceUse(MODE_BLUETOOTH, true);

        } else {

            if (scoReconnectedCount++ > MAX_scoReconnectedCount) {

                if (null != scoConnectedListener) {
                    scoConnectedListener.onBluetoothScoFailed();
                }
                return;
            }

            if (mAudioManager != null) {
                mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
                mAudioManager.setBluetoothScoOn(true);
                mAudioManager.startBluetoothSco();
                mAudioManager.setMicrophoneMute(false);
            }

        }


    }

    public void stopRecorderScoMode() {

        if (!DeviceAttr.getRunningDeviceAttr().hasBluetoothRecord()) {
            return;
        }

        DebugLog.e("stopRecorderScoMode....................");

        isScoConnected = false;

        scoReconnectedCount = 0;

        if (mUseNewInterface) {

            SettingsUtils.setBluetoothScoConnected(mContext, false);
            setForceUse(MODE_NONE, false);

        } else {

            if (mAudioManager != null) {
                mAudioManager.setMode(AudioManager.MODE_NORMAL);
                mAudioManager.stopBluetoothSco();
                mAudioManager.setBluetoothScoOn(false);

            }
        }

        if (scoConnectedListener != null) {
            scoConnectedListener.onBluetoothScoConnected(false);
        }

    }

    private int setForceUse(int usage, boolean record) {

        int config = FORCE_NONE;
        switch (usage) {
            case MODE_MIC | MODE_SPEAKER:
                config = record ? FORCE_MIC : FORCE_NONE;
                break;
            case MODE_BLUETOOTH:
                config = record ? FORCE_BT_SCO : FORCE_BT_A2DP;
                break;
            case MODE_HEADSET:
                config = record ? FORCE_WIRED_ACCESSORY : FORCE_HEADPHONES;
                break;
            default:
                break;
        }
        usage = record ? FOR_INPUT : FOR_OUTPUT;
//        DebugLog.e("setForceUse usage= " + usage + " config=" + config);
        Object obj = ReflectUtils.invokeMethodWithNoException("android.media.AudioSystem", "setForceUse", usage, config);
//        DebugLog.e("setForceUse obj = " + obj);
        if (obj instanceof Integer) {
            return (int) obj;
        }
        return -1;
    }


    public void registerBluetoothScoReceiver() {
        IntentFilter filter = new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
        mContext.registerReceiver(mBluetoothSCOReceiver, filter);
    }

    public void unregisterBluetoothScoReceiver() {
        mContext.unregisterReceiver(mBluetoothSCOReceiver);
    }

    private BroadcastReceiver mBluetoothSCOReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (isScoConnected || mUseNewInterface) {
                return;
            }

            if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(action)) {

                int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, AudioManager.SCO_AUDIO_STATE_ERROR);
                DebugLog.e("state = " + state);

                if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) {

                    isScoConnected = true;

                    if (scoConnectedListener != null) {
                        scoConnectedListener.onBluetoothScoConnected(true);
                    }

                } else {

                    startRecorderScoMode();

                }
            }
        }
    };
}
